
"""
J,M,S,X,W,P,B 分别代码车， 马， 士， 相， 将， 炮， 兵
开局的棋子：

J1, J2, M1, M2, S1, S2, X1, X2, W, P1, P2, B1, B2, B3, B4, B4

R 代表红方
B 代表黑方
J1 在1路
J2 在9路
右手边是1路， 左手边是9路
红方的1路是黑方的9路
位置描述， P1 的起始位置是 (2,3) 2路3线， 第一步， 炮2平5， 架当头炮。
第一步红方， 走棋描述为 ("RP1", (2, 3), (5, 3)), 2路炮移到5路
下一步棋，黑方走棋描述为 ("BP1", (2, 3), (5, 3)), 2路炮移到5路, 但这里的2路是黑方的8路。
"""
import datetime
import os
from functools import reduce

# 定义颜色的ANSI Escape序列
import time
from copy import deepcopy

from app import tools
from app.read_conf import base_dir

COLOR_RED = '\033[91m'
COLOR_GREEN = '\033[92m'
COLOR_YELLOW = '\033[93m'
COLOR_BLUE = '\033[94m'
COLOR_CYAN = '\033[96m'
COLOR_PURPLE = '\033[95m'
COLOR_GRAY = '\033[90m'
COLOR_RESET = '\033[0m'


class ChessGame(object):
    """
    piece_weight 各个棋子的权重
    """
    player_option = ("B", "R")
    piece_name = ('M1', 'M2', 'P1', 'P2', 'J1', 'J2', 'B1', 'B2', 'B3', 'B4', 'B5', 'S1', 'S2', 'X1', 'X2', 'W')
    ROW_NUM = 10
    COL_NUM = 9
    player_reverse_map = {
        'B': 'R',
        'R': 'B'
    }
    piece_weight = {
        "W": 100,
        "S": 3,
        "X": 3,
        "B": 1,
        "P": 5,
        "M": 5,
        "J": 10
    }

    def __init__(self, data=None):
        if data is None:
            # self.__status = [
            #     ["RJ1", "RM1", "RX1", "RS1", "RW", "RS2", "RX2", "RM2", "RJ2"],
            #     ["", "",  "",    "",    "",   "",    "",    "",    ""],
            #     ["",    "RP1", "",    "",    "",   "",    "",    "RP2", ""],
            #     ["RB1", "",    "RB2", "",    "RB3", "",   "RB4", "",    "RB5"],
            #
            #     ["", "", "", "", "", "", "", "", ""],
            #     ["", "", "", "", "", "", "", "", ""],
            #     ["BB5", "", "BB4", "", "BB3", "", "BB2", "", "BB1"],
            #     ["", "BP2", "", "", "", "", "", "BP1", ""],
            #     ["", "", "", "", "", "", "", "", ""],
            #     ["BJ2", "BM2", "BX2", "BS2", "BW", "BS1", "BX1", "BM1", "BJ1"],
            # ]

            self.__status = [
                ["BJ1", "BM1", "BX1", "BS1", "BW", "BS2", "BX2", "BM2", "BJ2"],
                ["", "", "", "", "", "", "", "", ""],
                ["", "BP1", "", "", "", "", "", "BP2", ""],
                ["BB1", "", "BB2", "", "BB3", "", "BB4", "", "BB5"],

                ["", "", "", "", "", "", "", "", ""],
                ["", "", "", "", "", "", "", "", ""],
                ["RB5", "", "RB4", "", "RB3", "", "RB2", "", "RB1"],
                ["", "RP2", "", "", "", "", "", "RP1", ""],
                ["", "", "", "", "", "", "", "", ""],
                ["RJ2", "RM2", "RX2", "RS2", "RW", "RS1", "RX1", "RM1", "RJ1"],
            ]

            self.__cur = "R"   # 定义那一方先走棋， 红方先走。
            self.__count = 0
            # self.__dead_game = False
            self.__dead_piece = []
        else:
            self.__status = deepcopy(data.get('status'))
            self.__cur = data.get('player')
            self.__count = data.get('count')
            self.__dead_piece = deepcopy(data.get('dead_piece'))

        self.__piece_index = {}
        self.build_piece_index()

        self.__player_attack = {
            'B': {},
            'R': {}
        }
        self.__player_attack_reverse = {
            'B': {},
            'R': {}
        }
        # self.build_piece_attack('B')
        # self.build_piece_attack('R')

    # @property
    # def dead_game(self):
    #     return self.__dead_game
    #
    # @dead_game.setter
    # def dead_game(self, flag):
    #     self.__dead_game = flag

    def get_status_piece(self, index):
        """根据数据索引获取棋子信息。
        :param index: 索引, 例如，[0,4]
        """
        i, j = index[:]
        return self.__status[i][j]

    def build_piece_index(self):
        """构建当前棋盘棋子的索引。
        """
        self.__piece_index = {}
        for i, row in enumerate(self.__status):
            for j, p in enumerate(row):
                if p:
                    self.__piece_index[p] = (i, j)

    def show_piece_index(self):
        for k, v in self.__piece_index.items():
            print("show_piece_index:", k, v)

    def get_piece_index(self, piece):
        """查找棋子的位置。
        :param piece: 棋子

        :return 返回位置， 例如， [2,5]
        """
        if not piece:
            return
        # self.build_piece_index()
        return self.__piece_index.get(piece)

    def _check_index_range(self, x):
        """检查坐标参数的合法范围。"""
        return 0 <= x[0] < self.ROW_NUM and 0 <= x[1] < self.COL_NUM

    def _cal_m_move_opt(self, index):
        """棋子马的粗略的走棋位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = ((i-2, j-1), (i-2, j+1), (i+2, j-1), (i+2, j+1),
                    (i-1, j-2), (i-1, j+2), (i+1, j-2), (i+1, j+2))
        move_opt = list(filter(lambda x: self._check_index_range(x), move_opt))
        print('m move_opt:', move_opt)
        return move_opt

    def _cal_b_move_opt(self, index):
        """棋子兵粗略的走棋的位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = ((i, j-1), (i, j+1), (i-1, j), (i+1, j))
        move_opt = list(filter(lambda x: self._check_index_range(x), move_opt))
        print('b move_opt:', move_opt)
        return move_opt

    def _cal_x_move_opt(self, index):
        """棋子象粗略的走棋的位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = ((i+2, j+2), (i+2, j-2), (i-2, j+2), (i-2, j-2))
        move_opt = list(filter(lambda x: self._check_index_range(x), move_opt))
        print('x move_opt:', move_opt)
        return move_opt

    def _cal_s_move_opt(self, index):
        """棋子士粗略的走棋的位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = ((i+1, j+1), (i+1, j-1), (i-1, j+1), (i-1, j-1))
        move_opt = list(filter(lambda x: self._check_index_range(x), move_opt))
        print('m move_opt:', move_opt)
        return move_opt

    def _cal_p_j_move_opt(self, index):
        """棋子炮，车粗略的走棋的位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = []
        for x in range(self.ROW_NUM):
            if x == i:
                continue
            move_opt.append((x, j))
        for x in range(self.COL_NUM):
            if x == j:
                continue
            move_opt.append((i, x))
        #
        print('p j move_opt:', move_opt)
        return move_opt

    def __xx_build_piece_attack(self, player):
        """Todo: 这个函数后面要重构， 把计算所有可能走法的代码抽出来，其他函数可以复用
        这个函数可以废弃了。
        """
        print = tools.dump_func
        print("\n======= start build_piece_attack")
        reverse_player = self.player_reverse_map.get(player)
        self.__player_attack[player] = {}
        self.__player_attack_reverse[reverse_player] = {}
        # 先建立所有棋子的位置信息，不用重复计算。
        self.build_piece_index()
        attack_piece_list = list(map(lambda x: player + x, self.piece_name))
        for piece in attack_piece_list:
            piece_index = self.get_piece_index(piece)
            print('build_piece_attack:', piece, piece_index)
            if not piece_index:
                continue
            move_opt = []
            check_rule = None

            if 'M' == piece[1]:
                move_opt = self._cal_m_move_opt(piece_index)
                check_rule = self.piece_m_rule
            elif 'P' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_p_rule
            elif 'J' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_j_rule
            elif 'B' == piece[1]:
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_b_rule
            elif 'X' == piece[1]:
                move_opt = self._cal_x_move_opt(piece_index)
                check_rule = self.piece_x_rule
            elif 'S' == piece[1]:
                move_opt = self._cal_s_move_opt(piece_index)
                check_rule = self.piece_s_rule
            elif 'W' == piece[1]:
                # 将的走棋规则跟兵相似， 这里借用兵的大致走棋规则
                # 可以增加对蒋吃子的规则。
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_w_rule

            for index in move_opt:
                # opt_pos = self.get_bord_pos(player, index)
                # print()
                opt_piece = self.get_status_piece(index)
                print('  opt_piece:', opt_piece, index)
                if not opt_piece or opt_piece[0] == player:
                    continue
                cur_pos = self.get_bord_pos(player, piece_index)
                target_pos = self.get_bord_pos(player, index)
                rv = check_rule((piece, cur_pos, target_pos))
                print('opt_piece:', index, opt_piece, rv)
                if 'OK' != rv:
                    continue

                if not self.__player_attack[player].get(piece):
                    self.__player_attack[player][piece] = []
                self.__player_attack[player][piece].append(opt_piece)
        #
        for k, v in self.__player_attack[player].items():
            for p in v:
                if not self.__player_attack_reverse[reverse_player].get(p):
                    self.__player_attack_reverse[reverse_player][p] = []
                self.__player_attack_reverse[reverse_player][p].append(k)

        print('__player_attack B:', self.__player_attack['B'])
        print('__player_attack R:', self.__player_attack['R'])

        print('__player_attack_reverse R:', self.__player_attack_reverse['R'])
        print('__player_attack_reverse B:', self.__player_attack_reverse['B'])

    def get_piece_attack(self):
        """根据双方所有可以走棋的选择， 计算双方可以攻击的棋子以及可以被攻击的棋子。
        计算局面得分信息规则：
        W - 10
        S - 3
        X - 2
        B - 1
        P - 4
        M - 5
        J - 8
        """
        cur_player = self.__cur
        opponent_player = self.player_reverse_map.get(cur_player)
        opt_move = self.get_player_opt_move(cur_player)
        opponent_opt_move = self.get_player_opt_move(opponent_player)
        attack_info = {
            'R': {},
            'B': {}
        }
        attack_info_backward = {
            'R': {},
            'B': {}
        }

        def update_attack_info(player, opt_move_data):
            player_reverse = self.player_reverse_map.get(player)
            player_attack_info = attack_info[player]
            player_attack_info_backward = attack_info_backward[player_reverse]

            for item in opt_move_data:
                move, target_piece = item[:]
                piece = move[0]

                if not self.piece_empty(target_piece):
                    if piece not in player_attack_info:
                        player_attack_info[piece] = []
                    player_attack_info[piece].append(target_piece)
                    #
                    if target_piece not in player_attack_info_backward:
                        player_attack_info_backward[target_piece] = []
                    player_attack_info_backward[target_piece].append(piece)

        update_attack_info(cur_player, opt_move)
        update_attack_info(opponent_player, opponent_opt_move)
        # 更新局面得分信息。
        attack_score = {
            "R": 0,
            "B": 0
        }
        attack_score_backward = {
            "R": 0,
            "B": 0
        }

        for player, info in attack_info.items():
            score = 0
            for p, v in info.items():
                score += sum([self.piece_weight.get(x[1]) for x in v])
            attack_score[player] = score

        for player, info in attack_info_backward.items():
            score = 0
            for p, v in info.items():
                score += self.piece_weight.get(p[1]) * len(v)
            attack_score_backward[player] = -score
        # 计算得分的差值
        # print()
        score_diff = {
            "R": attack_score["R"] + attack_score_backward["R"],
            "B": attack_score["B"] + attack_score_backward["B"],
        }

        return {
            'attack_info': attack_info,
            'attack_info_backward': attack_info_backward,
            'opt_move': opt_move,
            'attack_score': attack_score,
            'attack_score_backward': attack_score_backward,
            "score_diff": score_diff
        }

    def get_piece_defence(self):
        """获取棋子的防守信息。"""
        pass

    def get_player_opt_move_raw(self, player):
        """获取玩家所有的可能走法"""
        print = tools.dump_func
        opt_move = []
        self.build_piece_index()
        attack_piece_list = list(map(lambda x: player + x, self.piece_name))
        all_move_index = {}
        for piece in attack_piece_list:
            piece_index = self.get_piece_index(piece)
            print('build_piece_attack:', piece, piece_index)
            if not piece_index:
                continue
            move_opt = []
            check_rule = None

            if 'M' == piece[1]:
                move_opt = self._cal_m_move_opt(piece_index)
                check_rule = self.piece_m_rule
            elif 'P' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_p_rule
            elif 'J' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_j_rule
            elif 'B' == piece[1]:
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_b_rule
            elif 'X' == piece[1]:
                move_opt = self._cal_x_move_opt(piece_index)
                check_rule = self.piece_x_rule
            elif 'S' == piece[1]:
                move_opt = self._cal_s_move_opt(piece_index)
                check_rule = self.piece_s_rule
            elif 'W' == piece[1]:
                # 将的走棋规则跟兵相似， 这里借用兵的大致走棋规则
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_w_rule
            all_move_index[piece] = move_opt

        return all_move_index

    def get_player_opt_move(self, player):
        """获取玩家所有的可能走法"""
        print = tools.dump_func
        opt_move = []
        self.build_piece_index()
        attack_piece_list = list(map(lambda x: player + x, self.piece_name))
        for piece in attack_piece_list:
            piece_index = self.get_piece_index(piece)
            print('build_piece_attack:', piece, piece_index)
            if not piece_index:
                continue
            move_opt = []
            check_rule = None

            if 'M' == piece[1]:
                move_opt = self._cal_m_move_opt(piece_index)
                check_rule = self.piece_m_rule
            elif 'P' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_p_rule
            elif 'J' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_j_rule
            elif 'B' == piece[1]:
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_b_rule
            elif 'X' == piece[1]:
                move_opt = self._cal_x_move_opt(piece_index)
                check_rule = self.piece_x_rule
            elif 'S' == piece[1]:
                move_opt = self._cal_s_move_opt(piece_index)
                check_rule = self.piece_s_rule
            elif 'W' == piece[1]:
                # 将的走棋规则跟兵相似， 这里借用兵的大致走棋规则
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_w_rule

            for index in move_opt:
                # opt_pos = self.get_bord_pos(player, index)
                # print()
                opt_piece = self.get_status_piece(index)
                print('  opt_piece:', opt_piece, index)
                if not self.piece_empty(opt_piece) and opt_piece[0] == player:
                    continue
                cur_pos = self.get_bord_pos(player, piece_index)
                target_pos = self.get_bord_pos(player, index)
                rv = check_rule((piece, cur_pos, target_pos))
                print('  opt_piece check_rule:', index, opt_piece, rv)
                if 'OK' != rv:
                    continue
                """这里不能进行走子有效性的检查， 因为会调用这个self.get_piece_attack()函数导致循环调用。堆栈溢出。"""

                #
                opt_move.append([[piece, cur_pos, target_pos], opt_piece])
        # 可以吃子的着法先试
        opt_move_weight = [[x, 0 if not x[1] else self.piece_weight.get(x[1][1], 0)] for x in opt_move]
        opt_move_weight = sorted(opt_move_weight, key=lambda x: x[1], reverse=True)
        opt_move = [x[0] for x in opt_move_weight]
        return opt_move

    def get_player_opt_move_v2(self, player):
        """只选择相关棋子的走法。"""
        print = tools.dump_func
        opt_move = self.get_player_opt_move(player)
        attack_info = self.get_piece_attack()
        print(attack_info)
        print(player, self.cur_player)
        print(attack_info.get("attack_info").get(self.opponent_player))
        danger_piece_info = attack_info.get("attack_info").get(self.opponent_player)
        # for k, v in danger_piece_info.items():
        #     for target_piece in v:
        #         cur_pos = self.get_piece_pos(self.opponent_player, k)
        #         target_pos = self.get_piece_pos(self.opponent_player, target_piece)
        #         if not cur_pos or not target_pos:
        #             pass
        #             print("wrong data")
        #         move = [k, cur_pos, target_pos]   # 对方可能的攻击路径。
        #         print(move)
        # 简单检查吃子和被吃子的情况。 需要用递归方式来实现。
        # all_path = []
        # for i, item in enumerate(opt_move):
        #     attack = []   # 吃的棋子
        #     loss = []    # 被吃的棋子
        #     move, target_piece = item[:]
        #     if target_piece:
        #         attack.append(target_piece)
        #     # 走1步
        #     self.change_status_raw(move)
        #     attack1 = self.get_piece_attack()
        #     log_content = "%s: %s, %s" % (i, item, attack1.get("attack_info").get(self.opponent_player))
        #     print(log_content)
        #     # 安装对方的吃子的走法来推演。
        #     for k, v in attack1.get("attack_info").get(self.opponent_player).items():
        #         for target_loss in v:
        #             cur_pos = self.get_piece_pos(self.opponent_player, k)
        #             target_pos = self.get_piece_pos(self.opponent_player, target_loss)
        #             self.change_status_raw([k, cur_pos, target_pos])
        #             #
        #             attack2 = self.get_piece_attack()
        #             print("  %s, %s, %s" % ([k, cur_pos, target_pos], target_loss, attack2.get("attack_info").get(self.cur_player)))
        #             self.rewind_status_raw([k, cur_pos, target_pos], target_loss)
        #     self.rewind_status_raw(move, target_piece)
        # 1231
        all_path = []

        def traverse_attack(game, cur_player, move_path):
            attack3 = game.get_piece_attack()
            opponent_player = game.player_reverse_map.get(cur_player)
            cur_attack = attack3.get("attack_info").get(cur_player)
            # print(len(move_path), cur_attack)
            if not cur_attack:
                print("cur_attack is empty, return.")
                all_path.append(list(move_path))
                return
            if len(move_path) > 6:
                print("depth reach max, return.")
                all_path.append(list(move_path))
                return
            #
            print("traverse_attack:", cur_player, len(move_path), cur_attack)
            for k, v in cur_attack.items():
                for target_piece in v:
                    game.build_piece_index()
                    cur_pos = game.get_piece_pos(cur_player, k)
                    target_pos = game.get_piece_pos(cur_player, target_piece)
                    cur_move = [k, cur_pos, target_pos]
                    # print("  ", len(move_path), cur_move, target_piece)
                    game.change_status_raw(cur_move)
                    move_path.append([cur_move, target_piece])
                    traverse_attack(game, opponent_player, move_path)
                    move_path.pop()
                    game.rewind_status_raw(cur_move, target_piece)

        for i, item in enumerate(opt_move):
            move, target_piece = item[:]
            self.change_status_raw(move)
            traverse_attack(self, self.opponent_player, [item])
            self.rewind_status_raw(move, target_piece)
        print(all_path[:20], len(all_path))

        def cal_score(x):
            piece_list = [m[1] for m in x]

            score = 0
            piece_weight = {
                "B": 1,
                "M": 5,
                "P": 5,
                "J": 10,
                "S": 3,
                "X": 3,
                "W": 50,
            }
            for p in piece_list:
                if not p:
                    continue
                s = piece_weight.get(p[1])
                if p[0] == player:
                    score -= s
                else:
                    score += s
            print(piece_list, score)
            return score

        data = [[x[0], cal_score(x)] for x in all_path]
        data = sorted(data, key=lambda x:x[1], reverse=True)
        print(data[:200])
        # move_opt = [(tuple(x[0][0]), x[0][1]) for x in data[:200]]
        # print(move_opt[:2])
        # move_opt = list(set(move_opt))
        # print(move_opt, len(move_opt))
        move_hash = {}
        move_opt = []
        for item in data[:200]:
            str_move = tools.safe_json_dump(item[0])
            print(str_move)

            if str_move in move_hash:
                continue
            move_hash[str_move] = True
            move_opt.append(item[0])
            if len(move_opt) >= 10:
                break
        print(move_opt)

        # 当前可能被吃的棋子
        # danger_piece = reduce(lambda x, y: x+y, attack_info.get("attack_info").get(self.opponent_player).values())
        # # 去重计算
        # danger_piece = list(set(danger_piece))
        # print(danger_piece)
        # defence_pos_list = []
        # for item in danger_piece:
        #     defence_pos = self.get_piece_pos(player, item)
        #     print(defence_pos)

        # defence_pos_list = [self.get_piece_pos(player, item) for item in danger_piece]
        # print("defence_pos_list:", defence_pos_list)
        # for item in defence_pos_list:
        #     pass
        res = opt_move

        print("move_opt v2:", move_opt)
        return move_opt

    def check_move_valid(self, move):
        result = True
        target_piece = self.change_status_raw(move)

        # 检查对将的情况。
        self.build_piece_index()
        # self.show_piece_index()
        w_same_road = self.check_w_same_road()
        # print("check_w_same_road:", w_same_road)
        # 对将， 需要复原。
        if w_same_road:
            self.rewind_status_raw(move, target_piece)
            return False

        # 检查是否有将军的情况
        result = self.get_piece_attack()
        # print('attack info:', result)
        attack_info_backward = result.get('attack_info_backward').get(self.cur_player)

        # w_attacked = game.check_w_attacked(game.cur_player)
        w_attacked = (self.cur_player + 'W') in attack_info_backward
        # print("w_attacked:", w_attacked)
        if w_attacked:
            self.rewind_status_raw(move, target_piece)
            return False

        # 最后进行复原。
        self.rewind_status_raw(move, target_piece)
        return True

    def print_status(self):
        print("       ", end='')
        for c in range(len(self.__status[0])):
            print(f" {c+1}  ", end='')
        print("")
        for r, row in enumerate(self.__status):
            print(f"{r+1:<2}-{(9-r)+1:>2}| ", end="")
            for c, col in enumerate(row):
                col = col.strip()
                if not col:
                    col = '--'
                    print(f"{col:<4}", end='')
                elif "R" == col[0]:
                    print(COLOR_RED+f"{col:<4}"+COLOR_RESET, end='')
                else:
                    print(f"{col:<4}", end='')
            print("")

        print("       ", end='')
        for c in range(len(self.__status[0]), 0, -1):
            print(f" {c}  ", end='')
        print("")

    def get_status_pos(self, player, desc):
        """根据棋谱坐标计算内部数据索引. 这里是根据红方在上来计算的。
        2025/7/2 调整成红方在下， 跟国际惯例保持一致。
        """
        if player not in self.player_option:
            return "Error.WrongParam"
        if "R" == player:
            return 10 - desc[1], 9 - desc[0]
        elif "B" == player:
            return desc[1] - 1, desc[0] - 1

    def get_bord_pos(self, player, desc):
        """根据内部数据索引计算棋谱坐标"""
        if player not in self.player_option:
            return "Error.WrongParam"
        if "B" == player:
            return desc[1] + 1, desc[0] + 1
        elif "R" == player:
            return 9 - desc[1], 10 - desc[0]

    @classmethod
    def transform_board_coord(cls, status_coord, flag):
        x, y = status_coord[:]
        if flag:
            return x + 1, y + 1
        else:
            return 9 - x, 10 - y

    def get_bord_status(self):
        return {
            'status': self.__status,
            'player': self.__cur,
            'count': self.__count,
            # 'dead_game': self.__dead_game,
            # 'player_attack_reverse': self.__player_attack_reverse,
            # 'last_dead_piece': self.__dead_piece[-1:]
            'dead_piece': self.__dead_piece
        }

    def rewind_step(self, player, piece_move, target_piece):
        from_piece = piece_move[0]
        status_pos_from = self.get_status_pos(player, piece_move[1])
        status_pos_to = self.get_status_pos(player, piece_move[2])
        # last_dead_piece = self.__dead_piece[-1:]
        x1, y1 = status_pos_from[:]
        x2, y2 = status_pos_to[:]
        self.__status[x1][y1] = from_piece
        if not self.piece_empty(target_piece):
            self.__status[x2][y2] = target_piece
            self.__dead_piece.pop()
        self.__count -= 1

    def check_kill_game(self):
        """扫描所有可能的走棋"""
        cur_player = self.__cur
        opponent_player = self.player_reverse_map.get(cur_player)
        # 检查所有的可能的解法。
        print('start find opt move ...')
        opt_move = self.get_player_opt_move(cur_player)
        print('finish find opt move ...')
        attack_info = []
        all_result = []
        for move_desc in opt_move:
            # print("move_desc:", move_desc)
            target_piece = self.change_status_raw(move_desc[0])
            # 走了一步之后， 扫描对方所有可能的走法
            opponent_opt_move = self.get_player_opt_move(opponent_player)
            result = map(lambda x: True if x[1] and x[1][1] == 'W' else False, opponent_opt_move)

            # for opponent_move_desc in opponent_opt_move:
            #     print("    opponent_move_desc:", opponent_move_desc)
            # print('  opponent result:', list(result))
            all_result.append(any(result))
            self.rewind_status_raw(*move_desc)
            # self.print_status()

        # 每一种走棋， 对方都可以将军。表示死棋。
        if all(all_result):
            return True
        else:
            return False

    @classmethod
    def check_pos_valid(cls, desc):
        if 1 <= desc[0] <= 9 and 1 <= desc[1] <= 10:
            return True
        return False

    @classmethod
    def piece_empty(cls, piece):
        return not piece.strip()

    def have_piece(self, player, target_pos):
        """判断这个是否有棋子"""
        pieces = self.get_pos_piece(player, target_pos)
        if not self.piece_empty(pieces):
            return True
        return False

    def get_pos_piece(self, player, pos):
        x, y = self.get_status_pos(player, pos)
        # print("get_pos_piece:", player, pos, x, y)
        return self.__status[x][y]

    def check_w_same_road(self):
        player = self.__cur
        rw_pos = self.get_piece_pos(player, 'RW')
        bw_pos = self.get_piece_pos(player, 'BW')

        if rw_pos and bw_pos and rw_pos[0] == bw_pos[0]:
            piece_num = self.get_road_piece_num(player, rw_pos[0], rw_pos[1], bw_pos[1])
            if 0 == piece_num:
                return True
        return False

    @property
    def cur_player(self):
        """获取当前的执棋方。 """
        return self.__cur

    @property
    def opponent_player(self):
        """获取对方的玩家。 """
        return self.player_reverse_map.get(self.__cur)

    def change_status_raw(self, move):
        """这个函数只是单纯的改变状态， 大部分情况下， 改变状态后， 还需要检查其他规则，如果不符合规则，需要回退状态。
        返回值是目标位置的棋子。"""
        #
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        #
        x, y = self.get_status_pos(player, cur_pos)[:]
        self.__status[x][y] = ""
        x2, y2 = self.get_status_pos(player, target_pos)[:]
        target_piece = self.__status[x2][y2]
        if not self.piece_empty(target_piece):
            self.__dead_piece.append(target_piece)
        self.__status[x2][y2] = piece
        return target_piece

    def rewind_status_raw(self, move, target_piece):
        """这个函数是回退的操作.
        @param move  上一步操作的数据。
        @param target_piece 是上一步操作目标位置的棋子。"""
        #
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        #
        x1, y1 = self.get_status_pos(player, cur_pos)[:]
        x2, y2 = self.get_status_pos(player, target_pos)[:]

        self.__status[x1][y1] = piece
        if not self.piece_empty(target_piece):
            self.__status[x2][y2] = target_piece
            dead_piece = self.__dead_piece.pop()
            assert dead_piece == target_piece
        else:
            self.__status[x2][y2] = ""

    def piece_p_rule(self, move):
        """炮的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        # 炮也只能走直线。
        if road != road2 and line != line2:
            return "Error.WrongMove"
        # 前进或后退
        elif road == road2:
            piece_num = self.get_road_piece_num(player, road, line, line2)
        # 平移
        elif line == line2:
            # 有两种情况， 一种是路线是空的
            piece_num = self.get_line_piece_num(player, line, road, road2)
        else:
            return "Error.WrongMove"
        #
        target_piece = self.get_pos_piece(player, target_pos)
        if piece_num > 1:
            return "Error.WrongMove"
        if piece_num == 0 and not self.piece_empty(target_piece):
            return "Error.WrongMove"
        if piece_num == 1 and self.piece_empty(target_piece):
            return "Error.WrongMove"
        if self.piece_same_player(player, target_pos):
            return "Error.WrongMove"
        # return self.change_status(move)
        # return "OK"
        return "OK"

    def piece_same_player(self, player, target_pos):
        """判断目标位置是否是己方棋子"""
        target_piece = self.get_pos_piece(player, target_pos)
        print('piece_same_player:', target_pos, player, target_piece)
        #
        if not self.piece_empty(target_piece):
            target_player = target_piece[0]
            if target_player == player:
                return True
        return False

    def piece_m_rule(self, move):
        """马的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if abs(road - road2) == 1 and abs(line - line2) == 2:
            if line2 > line:   # 进马
                m_leg_pos = (road, line + 1)  # 马腿位置
                m_leg_piece = self.get_pos_piece(player, m_leg_pos)
            else:
                m_leg_pos = (road, line - 1)  # 马腿位置
                m_leg_piece = self.get_pos_piece(player, m_leg_pos)

            if not self.piece_empty(m_leg_piece):
                return "Error.WrongMove"
            target_piece = self.get_pos_piece(player, target_pos)
            #
            if not self.piece_empty(target_piece):
                target_player = target_piece[0]
                if target_player == player:
                    return "Error.WrongMove"
            # return self.change_status(move)
            return "OK"

        elif abs(road - road2) == 2 and abs(line - line2) == 1:
            if road > road2:  #
                m_leg_pos = (road - 1, line)  # 马腿位置
            else:
                m_leg_pos = (road + 1, line)  # 马腿位置
            #
            # print("m_leg_pos:", m_leg_pos)
            if self.have_piece(player, m_leg_pos):
                return "Error.WrongMove.Barrier"
            if self.piece_same_player(player, target_pos):
                return "Error.WrongMove"
            #
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"

        # return "OK"

    def piece_b_rule(self, move):
        """兵的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if road == road2:  # 进兵
            if line2 == line + 1:
                if not self.piece_same_player(player, target_pos):
                    # return self.change_status(move)
                    return "OK"
                else:
                    return "Error.WrongMove"
            else:
                return "Error.WrongMove"
        elif line == line2 and line > 5:  # 兵平移, 过河兵才可以平移
            if not (abs(road - road2) == 1):
                return "Error.WrongMove"
            # elif self.piece_same_player(player, target_pos):
            #     return "Error.WrongMove"
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"
        #
        # return "OK"

    def empty_road(self, player, road, line, line2):
        start = min(line, line2)
        end = max(line, line2)
        empty_flag = True
        for i in range(start+1, end, 1):
            temp_piece = self.get_pos_piece(player, (road, i))
            if not self.piece_empty(temp_piece):
                empty_flag = False
                break
        return empty_flag

    def get_road_piece_num(self, player, road, line, line2):
        """计算某一路上棋子的个数。 """
        start = min(line, line2)
        end = max(line, line2)
        piece_num = 0
        for i in range(start + 1, end, 1):
            temp_piece = self.get_pos_piece(player, (road, i))
            if not self.piece_empty(temp_piece):
                piece_num += 1
        return piece_num

    def get_line_piece_num(self, player, line, road, road2):
        """计算某一线上棋子的个数。 """
        start = min(road, road2)
        end = max(road, road2)
        piece_num = 0
        for i in range(start + 1, end, 1):
            temp_piece = self.get_pos_piece(player, (i, line))
            if not self.piece_empty(temp_piece):
                piece_num += 1
        return piece_num

    def empty_line(self, player, line, road, road2):
        print = tools.dump_func
        print("empty_line:", line, road, road2)
        start = min(road, road2)
        end = max(road, road2)
        print("start:", start, end)
        empty_flag = True
        for i in range(start+1, end, 1):
            print("road:", i)
            temp_piece = self.get_pos_piece(player, (i, line))
            if not self.piece_empty(temp_piece):
                empty_flag = False
                break
        return empty_flag

    def piece_j_rule(self, move):
        """车的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        # print("piece_j_rule:", move)

        # 这个是通用判断， 可以放到外层去。
        if self.piece_same_player(player, target_pos):
            return "Error.WrongMove"
        #
        if road == road2:  # 前进或后退
            # print("j_rule:", player, road, line, line2)
            if not self.empty_road(player, road, line, line2):
                return "Error.WrongMove"
            # return self.change_status(move)
            return "OK"
        elif line == line2:  # 平移
            if not self.empty_line(player, line, road, road2):
                return "Error.WrongMove.Barrier"
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"
        # return "OK"

    def piece_x_rule(self, move):
        """象的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if line2 > 5:   # 象不能过河
            return "Error.WrongMove"
        # print("piece_j_rule")
        if abs(road - road2) == 2 and abs(line - line2) == 2:
            # 象眼的位置
            x_eye_pos = ((road + road2) // 2, (line + line2) // 2)
            if self.have_piece(player, x_eye_pos):
                return "Error.WrongMove.Barrier"
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"

    def piece_s_rule(self, move):
        """士的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if line2 > 3 or road2 < 4 or road2 > 6:   # 士只能在九宫格内活动
            return "Error.WrongMove"
        # print('piece_s_rule:', abs(road - road2), abs(line - line2))
        if (abs(road - road2) == 1) and (abs(line - line2) == 1):
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"

        # return "OK"

    def get_piece_pos(self, player, piece):
        """status_index 表示内部二维列表的索引坐标， board_pos 一般表示棋盘坐标，是跟执棋方相关的。 """
        status_index = self.get_piece_index(piece)
        if not status_index:
            return None
        return self.get_bord_pos(player, status_index)
        # for i, r in enumerate(self.__status):
        #     for j, p in enumerate(r):
        #         if p == piece:
        #             # print('get_piece_pos:', (i, j))
        #             return self.get_bord_pos(player, (i, j))

    def piece_w_rule(self, move):
        """老蒋的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if line2 > 3 or road2 < 4 or road2 > 6:   # 老蒋只能在九宫格内活动
            return "Error.WrongMove"
        # print('piece_s_rule:', abs(road - road2), abs(line - line2))
        if ((road == road2) and (abs(line - line2) == 1)) or ((line == line2) and (abs(road - road2) == 1)):
            # w_pos = None
            # if 'B' == player:
            #     w_pos = self.get_piece_pos(player, 'RW')
            # elif 'R' == player:
            #     w_pos = self.get_piece_pos(player, 'BW')
            # #
            # if not w_pos:
            #     return "Error.ProcWrong"
            # print('w_pos:', w_pos)
            # if w_pos[0] == road2:
            #     return "Error.WrongMove"
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"

    def switch_player_raw(self):
        """只是切换角色，但是计数不增加。用于算法模拟计算的情况。 """
        if "B" == self.__cur:
            self.__cur = "R"
        elif "R" == self.__cur:
            self.__cur = "B"

    def switch_player(self):
        if "B" == self.__cur:
            self.__cur = "R"
        elif "R" == self.__cur:
            self.__cur = "B"
        self.__count += 1

    def evaluate(self, side):
        """评估当前棋局的形势得分。 最简单的算法，根据棋子的多少来计算分值。 """
        self.build_piece_index()
        score = {
            "R": 0,
            "B": 0
        }
        for p, v in self.__piece_index.items():
            player = p[0]
            piece_type = p[1]
            score[player] += self.piece_weight.get(piece_type)
        if 'R' == side:
            return score['R'] - score['B']
        elif 'B' == side:
            return score['B'] - score['R']

    def get_min_max_move(self, player):
        """获取最大值最小值算法计算的结果。
        日志保存到文件中。 """
        log_content = []
        # print = tools.dump_func
        print("get_min_max_move:", player)
        game = self
        log_content.append("get_min_max_move: player=%s, game_player=%s" % (player, game.cur_player))
        min_value = -2**20
        max_value = 2**20

        # 记录走子的路径
        move_stack = []
        side = game.cur_player

        cal_depth = 4

        def min_max(depth, know_max, know_min):
            print("min_max: depth=%s, know_max=%s, know_min=%s" % (depth, know_max, know_min))
            log_content.append("min_max: depth=%s, know_max=%s, know_min=%s" % (depth, know_max, know_min))
            if game.cur_player == player:
                return get_max(depth, know_min, [])
            else:
                return get_min(depth, know_max, [])

        def get_max(depth, know_min, root_move):
            """
            :param depth:
            :param know_min:
            :param root_move: 之前走棋的步骤。
            :return:
            参考实现
            int Max(int depth, int KnownMin) {
                int best = -INFINITY;
                // 获取当前局面的得分。
                if (depth <= 0)
                    return Evaluate();
                // 列举所有可能的走法
                GenerateLegalMoves();

                while (hasLegalNext()) {
                    MakeNextMove();
                    val = Min(depth - 1, best);//将 当前最大值 传递成为 子递归的已知最大值
                    UnmakeMove();
                    if (val > best) best = val;//得到当前最大值
                    if (best >= KnownMin) return KnownMin;//与已知最大值比较，若已知最小值 小于等于 当前最大值，则返回已知最小值。
                }
                return best;
            }
            """
            print("get_max: depth=%s, know_min=%s" % (depth, know_min))
            start_space = ' ' * ((cal_depth - depth + 1)*2)
            log_content.append("%sget_max: depth=%s, know_min=%s" % (start_space, depth, know_min))
            best = min_value
            if depth <= 0:
                e = game.evaluate(side)
                print("get_max: evaluate=%s" % e)
                return e, []
            cur_player = game.cur_player
            opt_move = game.get_player_opt_move(cur_player)

            # opt_move = [x for x in opt_move if game.check_move_valid(x[0])]
            print("get_max: move size=%d, player=%s" % (len(opt_move), cur_player))
            log_content.append("%sget_max: move size=%d, player=%s" % (
                start_space, len(opt_move), cur_player))
            session_id = tools.get_random_str(6)
            log_content.append("%sget_max: opt_move data show below:" % start_space)
            for i, item in enumerate(opt_move):
                log_content.append("%s=>%s: %s" % (start_space, i, item))
            sel_move = None
            sel_move_depth = []
            for i, item in enumerate(opt_move):
                move, piece = item[:]
                # print("get_max: depth=%s, index=%d/%d, root_move=%s, move=%s" % (
                #     depth, i, len(opt_move), root_move, item))
                target_piece = game.change_status_raw(move)
                game.switch_player_raw()
                root_move.append(item)
                val, move_depth = get_min(depth - 1, best, root_move)
                root_move.pop()
                game.rewind_status_raw(move, target_piece)
                game.switch_player_raw()
                print("get_max: depth=%s, index=%d/%d, score=%s, best=%s, root_move=%s, move=%s， move_depth=%s" % (
                    depth, i, len(opt_move), val, best, root_move, item, move_depth))
                log_content.append("%s=>get_max for loop %s: depth=%s, index=%d/%d, score=%s, best=%s, root_move=%s, "\
                                   "move=%s， move_depth=%s" % (start_space, session_id, depth, i, len(opt_move), val, best,
                                                               root_move, item, move_depth))
                if val > best:
                    best = val
                    sel_move = item
                    sel_move_depth = move_depth
                if best >= know_min:
                    print("get_max: return, depth=%d, best=%d, move=%s" % (depth, know_min, sel_move))
                    log_content.append("%s => get_max for loop: return, depth=%d, best=%d, move=%s" % (
                        start_space, depth, know_min, sel_move))
                    return know_min, [sel_move] + sel_move_depth
            print("get_max: return, depth=%d, best=%d, move=%s" % (depth, best, sel_move))
            log_content.append("%sget_max: return, depth=%d, best=%d, move=%s" % (start_space, depth, best, sel_move))
            return best, [sel_move] + sel_move_depth

        def get_min(depth, know_max, root_move):
            """
            :param depth:
            :param know_max:
            :param root_move: 之前的走棋步骤
            :return:
            参考实现。
            int Min(int depth, int KnownMax) {
                int best = INFINITY;
                if (depth <= 0) return Evaluate();
                GenerateLegalMoves();
                while (hasLegalNext()) {
                    MakeNextMove();
                    val = Max(depth - 1, best);//将 当前最小值 传递成为 子递归的已知最小值
                    UnmakeMove();
                    if (val < best) best = val;//得到当前最小值
                    if (best <= KnownMax) return KnownMax;//与已知最大值比较，若已知最大值 大于等于 当前最小值，则返回已知最大值
                }
                return best;
            }
            """
            print("get_min: depth=%s, know_max=%s" % (depth, know_max))
            start_space = ' ' * ((cal_depth - depth + 1) * 2)
            log_content.append("%sGET_MIN: depth=%s, know_max=%s" % (start_space, depth, know_max))
            best = max_value
            if depth <= 0:
                e = game.evaluate(side)
                print("get_min: evaluate=%s" % e)
                return e, []
            cur_player = game.cur_player
            opt_move = game.get_player_opt_move(cur_player)
            # opt_move = [x for x in opt_move if game.check_move_valid(x[0])]
            # opt_move = list(filter(lambda x: game.check_move_valid(x[0]), opt_move))
            # for item in opt_move:
            #     game.check_move_valid()

            print("get_min: move size=%d, player=%s" % (len(opt_move), cur_player))
            log_content.append("%sGET_MIN: move size=%d, player=%s" % (start_space, len(opt_move), cur_player))

            session_id = tools.get_random_str(6)
            log_content.append("%sGET_MIN: opt_move data show below:" % start_space)
            for i, item in enumerate(opt_move):
                log_content.append("%s=>%s: %s" % (start_space, i, item))

            sel_move = None
            sel_move_path = []
            for i, item in enumerate(opt_move):
                move, piece = item[:]
                # print("get_min: depth=%s, index=%d/%d, root_move=%s, move=%s, piece=%s" % (
                #     depth, i, len(opt_move), root_move, move, piece))
                # print("get_min: move:", move)
                target_piece = game.change_status_raw(move)
                game.switch_player_raw()
                root_move.append(item)
                val, move_depth = get_max(depth - 1, best, root_move)
                root_move.pop()
                game.rewind_status_raw(move, target_piece)
                game.switch_player_raw()
                print("get_min: depth=%s, index=%d/%d, score=%s, best=%s, root_move=%s, move=%s, move_depth=%s" % (
                    depth, i, len(opt_move), val, best, root_move, item, move_depth))
                log_content.append("%s=>GET_MIN for loop %s: depth=%s, index=%d/%d, score=%s, "
                                   "best=%s, root_move=%s, "
                                   "move=%s, move_depth=%s" % (start_space, session_id, depth, i, len(opt_move), val,
                                                               best, root_move, item, move_depth))
                if val < best:
                    best = val
                    sel_move = item
                    sel_move_path = move_depth
                if best <= know_max:
                    print("get_min: return, depth=%d, best=%d, move=%s" % (depth, know_max, sel_move))
                    log_content.append("%sGET_MIN: return, depth=%d, best=%d, know_max=%s, move=%s" % (
                        start_space, depth, best, know_max, sel_move))
                    return best, [sel_move] + sel_move_path
            print("get_min: return, depth=%d, best=%d, move=%s" % (depth, best, sel_move))
            log_content.append("%sGET_MIN: return, depth=%d, best=%d, move=%s" % (start_space, depth, best, sel_move))
            return best, [sel_move] + sel_move_path

        res = min_max(cal_depth, min_value, max_value)

        # 保存日志
        dt = datetime.datetime.now()
        log_path = os.path.join(base_dir, "log", "%s.log" % dt.strftime("%Y%m%d%H%M%S"))
        print(log_path, log_content[:2])
        with open(log_path, "wb") as fo:
            fo.write("\n".join(log_content).encode('utf8'))
        print("res:", res)
        return res

    def step_check(self, move):
        """象棋走一步棋的处理。
        :param move:  走棋的描述。 格式为（棋子，当前位置， 目标位置）
        """
        piece, cur_pos, target_pos = move[:]
        # 走棋位置的检查，要在棋盘范围内。
        if not self.check_pos_valid(cur_pos) or not self.check_pos_valid(target_pos):
            return "Error.WrongData.InvalidPos"

        # 目标位置是同一方的棋子是无效数据
        player = piece[0]
        if self.piece_same_player(player, target_pos):
            return "Error.WrongMove.SamePlayerPiece"
        # 位置没有变化是无效数据, 判断走棋规则用象棋术语坐标。
        # 判断棋盘的状态用， 内部的数组索引。
        if cur_pos == target_pos:
            return "Error.WrongData.SamePos"
        # 走棋是否是当前下棋方。
        if player != self.__cur:
            return "Error.WrongData.WrongPlayer"
        # 棋子正确性的检查
        cur_piece = self.get_pos_piece(player, cur_pos)
        if piece != cur_piece:
            return "Error.WrongData.PieceWrong"
        #
        # 移动的目标位置。
        piece_type = piece[1]

        # 棋子是车
        res = "Error"
        #  棋子是炮
        if "P" == piece_type:
            res = self.piece_p_rule(move)
        elif "M" == piece_type:
            res = self.piece_m_rule(move)
        elif "B" == piece_type:
            res = self.piece_b_rule(move)
        elif "J" == piece_type:
            res = self.piece_j_rule(move)
        elif "X" == piece_type:
            res = self.piece_x_rule(move)
        elif "S" == piece_type:
            res = self.piece_s_rule(move)
        elif 'W' == piece_type:
            res = self.piece_w_rule(move)

        # 把下面这些逻辑移出这个函数。
        # if "OK" == res:
        #     res = self.change_status(move)
        #     if 'OK' != res:
        #         return res
        #
        # self.build_piece_index()
        # # self.build_piece_attack('B')
        # # self.build_piece_attack('R')
        #
        # # self.scan_attack()
        # self.switch_player()

        return res

    def get_uci_pos(self):
        """获取UCI协议的棋子位置表示。"""
        data = self.get_bord_status()
        status = data.get("status")
        # for line in status:
        #     print(line)
        uci_pos = []
        uci_piece_map = {
            "J": "r",
            "M": "n",
            "X": "b",
            "S": "a",
            "W": "k",
            "P": "c",
            "B": "p"
        }
        for line in status:
            empty = 0
            uci_line = ""
            for p in line:
                if not p:
                    empty += 1
                else:
                    piece = p[1]
                    uci_piece = uci_piece_map.get(piece)
                    if "R" == p[0]:
                        uci_piece = uci_piece.upper()
                    if empty > 0:
                        uci_line += "%s%s" % (empty, uci_piece)
                    else:
                        uci_line += "%s" % uci_piece
                    empty = 0
            if empty > 0:
                uci_line += "%s" % empty

            uci_pos.append(uci_line)
        #
        return "/".join(uci_pos)
        # print("/".join(uci_pos))

    def get_move_from_uci_coord(self, player, uci_coord):
        from_i = 9 - int(uci_coord[1])
        from_j = ord(uci_coord[0]) - ord('a')
        to_i = 9 - int(uci_coord[3])
        to_j = ord(uci_coord[2]) - ord('a')
        print("from_i:", from_i, from_j, to_i, to_j)
        from_pos = self.get_bord_pos(player, [from_i, from_j])
        to_pos = self.get_bord_pos(player, [to_i, to_j])
        piece = self.get_pos_piece(player, from_pos)
        return piece, from_pos, to_pos


def main():
    game = ChessGame()
    game.print_status()
    move_set = (
        ("BP1", (2, 3), (5, 3)),
        ("RP1", (2, 3), (5, 3)),
        ("BM1", (2, 1), (3, 3)),
        ("RB4", (7, 4), (7, 5)),
        ("BJ1", (1, 1), (2, 1)),
        ("RM2", (8, 1), (7, 3)),
        ("BJ1", (2, 1), (2, 5)),
        ("RM1", (2, 1), (3, 3)),
        ("BB2", (3, 4), (3, 5)),
        ("RJ1", (1, 1), (2, 1)),
        ("BP2", (8, 3), (7, 3)),
        ("RJ1", (2, 1), (2, 7)),
        ("BB4", (7, 4), (7, 5)),
        ("RJ1", (2, 7), (3, 7)),
        ("BB2", (3, 5), (3, 6)),
        ("RB2", (3, 4), (3, 5)),
        ("BB4", (7, 5), (7, 6)),
        ("RJ1", (3, 7), (3, 5)),
        ("BB2", (3, 6), (3, 7)),
        ("RM2", (7, 3), (5, 2)),
        ("BJ1", (2, 5), (6, 5)),
        ("RM1", (3, 3), (4, 5)),
        ("BP1", (5, 3), (5, 7)),
        ("RP2", (8, 3), (9, 3)),
        ("BX2", (7, 1), (5, 3)),
        ("RM1", (4, 5), (3, 3)),
        ("BB2", (3, 7), (4, 7)),
        # ("RJ2", (9, 1), (8, 1)),
        # ("BM1", (3, 3), (4, 5)),
        # ("RJ1", (3, 5), (6, 5)),
        # ("BB2", (4, 7), (3, 7)),
        # ("RJ2", (8, 1), (8, 4)),
        # ("BB2", (4, 7), (3, 7)),
        # ("RJ1", (3, 5), (3, 4)),
        ("RM1", (3, 3), (5, 4)),
        ("BB2", (4, 7), (5, 7)),
        ("RP1", (5, 3), (3, 3)),
        ("BP2", (7, 3), (7, 8)),
        ("RJ1", (3, 5), (3, 3)),

    )
    print("\033c", end="")
    game.print_status()
    # time.sleep(1)

    for i, move in enumerate(move_set):
        # os.system("clear")
        print("\033c", end="")
        if i == len(move_set) - 1:
            print("debug stop!")
        res = game.step(move)    # 炮2平5
        print("res:", res)
        if "OK" == res:
            print("\n==================== step:", i + 1)
            game.print_status()
        # time.sleep(1.5)


def test_print_with_color():
    # 定义颜色的ANSI Escape序列
    # COLOR_RED = '\033[91m'
    # COLOR_GREEN = '\033[92m'
    # COLOR_YELLOW = '\033[93m'
    # COLOR_BLUE = '\033[94m'
    # COLOR_CYAN = '\033[96m'
    # COLOR_PURPLE = '\033[95m'
    # COLOR_GRAY = '\033[90m'
    # COLOR_RESET = '\033[0m'

    # 打印带有颜色的文本
    print(COLOR_RED + "红色文本" + COLOR_RESET)
    print(COLOR_GREEN + "绿色文本" + COLOR_RESET)
    print(COLOR_YELLOW + "黄色文本" + COLOR_RESET)


def chess_analysis(game):
    """
    怎么分析当前的棋局形势。
    1 第一步， 分析自己被攻击的棋子。怎么解救棋子。
    """
    info = game.get_piece_attack()
    print("info:", info)
    print("info:", info.keys())

    # opt_player = game.opponent_player
    cur_player = game.cur_player
    be_attacked = info.get("attack_info_backward").get(cur_player)
    be_attacked_piece = be_attacked.keys()
    print("be_attacked_piece:", be_attacked_piece)

    opt_move = info.get("opt_move")
    cur_player = game.cur_player
    oppo_player = game.opponent_player
    print("opt move:")
    res = {}
    for i, item in enumerate(opt_move):
        print("=== sep ===")
        print(item)
        temp_move, target_piece = item[:]
        # temp_status = game.get_bord_status()
        str_move = json.dumps(item)
        res[str_move] = 1
        check_rv = game.step_check(temp_move)
        print("check_rv:", i, check_rv)
        if "OK" != check_rv:
            continue
        game.change_status_raw(temp_move)
        # 走了这步棋之后， 计算吃子和被吃子
        temp_info = game.get_piece_attack()
        temp_attack = temp_info.get("attack_info").get(cur_player)
        temp_be_attacked = temp_info.get("attack_info_backward").get(cur_player)
        print(f"temp_attack:{i}, {item}, {temp_attack}, {temp_be_attacked}")
        game.rewind_status_raw(temp_move, target_piece)


def test_build_attack_piece():
    game = ChessGame()
    # print(game.get_bord_status())
    game.print_status()
    move = ("RP1", (2, 3), (5, 3))
    res = game.step_check(move)
    print("res:", res)
    game.change_status_raw(move)
    #  这中间其实还没有处理对将和被将的情况的检查。
    game.switch_player()
    game.print_status()

    data = game.get_bord_status()
    # print("data:", json.dumps(data.get("status"), indent=2))
    # reverse_status = []
    # for line in data.get("status"):
    #     reverse_status.append(line[::-1])
    # reverse_status.reverse()
    #
    # chess_analysis(game)
    # res = game.get_player_opt_move_raw(game.cur_player)
    # print("res:", res)
    # res = game.get_player_opt_move(game.cur_player)
    # print("res:", res)
    # for item in res:
    #    print(item)
    uci_pos = game.get_uci_pos()
    print("uci_pos:", uci_pos)
    # 计算的走法 h9g7， 怎么转换成 本地的格式。


if __name__ == "__main__":
    # main()
    # test_print_with_color()
    test_build_attack_piece()

